#include "Entity.h"
#include "Game.h"

Entity::Entity(SpawnInfo spawnInfo)
{
    lastTickTime = SDL_GetTicks();

	x = spawnInfo.x;
	y = spawnInfo.y;

	u = 0;
	v = 0;

	flipped = false;

	health = 25;
	alive = true;

	applyGravity = true;

	expired = false;

	walkingSpeed = 4;

	pointsValue = 0;
}

Entity::~Entity()
{
	
}

void Entity::moveLeft(){
    x -= walkingSpeed;

    if( x < 0 ) x = 0;
}

void Entity::moveRight(){
    x += walkingSpeed;
    //u = 5;
}

void Entity::processForces()
{
    x += (int) u;
    y += (int) v;

	// Gravity
	if(applyGravity) v -= G;

    // If hit the floor
    if(y <= 0){
		y = 0;	// Stop entity from going through the floor

		if(!alive){
			// If the entity is dead, make them bounce a bit when they hit the deck
			v = v * -0.3f;
			if(fabsf(v) < 0.3f) v = 0.0f;
		}else{
			// If alive then don't bounce
			v = 0;
		}
        
        touchingGround = true;
	}else{
		touchingGround = false;
	}

	if(touchingGround)
	{
		int uDec = 1;

		if(abs((int)u) < uDec){
			u = 0;
		} else if (u < 0){
			u += uDec;
		} else if (u > 0){
			u -= uDec;
		}
	}


}

BBox Entity::getBoundingBox()
{
    Image* image = getCurrentImage();

    BBox r;
	// Convert to screen coordinates to stop me getting confused
	r.x = Viewport::drawX( x - image->getRefX() );
	r.y = Viewport::drawY( y + image->getRefY() );

	r.w = image->getWidth();
    r.h = image->getHeight();

    return r;
}

bool Entity::collidesWith(Entity* other)
{
	assert(other != NULL);

	// Let's ensure this entity is always to the left of the other one
	if( x > other->getX() ) return other->collidesWith(this);

	BBox thisBox = getBoundingBox();
	BBox otherBox = other->getBoundingBox();
	BBox intersection = thisBox.getIntersection( & otherBox );

	if(intersection.isEmpty()) return false;

	Image* im = getCurrentImage();
	byte** thisMap = im->getCollisionMap();

	Image* otherIm = other->getCurrentImage();
	byte** otherMap = otherIm->getCollisionMap();

	assert(thisMap != NULL);
	assert(otherMap != NULL);

	/*for(int xx=0; xx<currentImage->getWidth(); xx++){
		for(int yy=0;yy< currentImage->getHeight(); yy++){
			int dx = Viewport::drawX((flipped ? currentImage->getWidth()-1-xx : xx) + thisBox.x);
			int dy = Viewport::drawY((currentImage->getHeight()-yy) + thisBox.y);
			if(thisMap[xx][yy] != 0) glRecti(dx,dy,dx+1,dy+1);
		}
	}*/

	for(int y= intersection.y; y < intersection.y + intersection.h; y++)
	{
		int thisY = y - thisBox.y;
		int otherY = y - otherBox.y;
		for(int x= intersection.x; x< intersection.x+intersection.w; x++)
		{
			if(
				im->collisionAt( x-thisBox.x, thisY, flipped ) &&
				otherIm->collisionAt( x-otherBox.x, otherY, other->isFlipped() )
			) return true;
		}
	}

	return false;
}

bool Entity::withinRange()
{
	int drawX = Viewport::drawX(x);
	return (drawX > -50 && drawX < Window::getInstance()->getWidth() + 50);
}

void Entity::maybeTick()
{
    Uint32 now = SDL_GetTicks();
	if(withinRange() && now - lastTickTime > 30)
    {
        lastTickTime = now;
        tick();
        processForces();
    }
}

void Entity::draw()
{
    int dx = Viewport::drawX(x);
    int dy = Viewport::drawY(y);
	Image* currentImage = getCurrentImage();

	Uint32 now = SDL_GetTicks();

	// If alive of died less than 5 seconds ago
	if(alive || now - timeOfDeath < ENTITY_TIME_BEFORE_FADEOUT)
	{
		// Full alpha
		currentImage->setAlpha(255);
	}
	else
	{
		// Fade out over 3 seconds
		int alpha = (int) (255 - ( (float)(now-timeOfDeath-ENTITY_TIME_BEFORE_FADEOUT) / ENTITY_FADEOUT_DURATION ) * 255);
		if(alpha < 0){
			expired = true;
			alpha = 0;
		}
		currentImage->setAlpha( alpha );
	}

	/*BBox thisBox = getBoundingBox();
	byte** thisMap = currentImage->getCollisionMap();

	glColor4f(0,0,1,0.5f);
	for(int xx=0; xx<currentImage->getWidth(); xx++){
		for(int yy=0;yy< currentImage->getHeight(); yy++){
			int dx = Viewport::drawX((flipped ? thisBox.w-1-xx : xx) + thisBox.x);
			int dy = Viewport::drawY((thisBox.h-yy) + thisBox.y);
			dx = (flipped ? thisBox.w-1-xx : xx) + thisBox.x;
			dy = yy + thisBox.y;
			if(thisMap[xx][yy] != 0) glRecti(dx,dy,dx+1,dy+1);
		}
	}*/

	currentImage->draw(dx,dy,flipped);
}

void Entity::damage(byte amount, Entity* attacker, bool knockBack)
{
	// Can't hurt anyone who's recoiling or dead
	// TODO: make recoiling variable to use instead of u == 0?
	if(!alive || u != 0) return;

	if(health - amount <= 0)
	{
		health = 0;
		v = 5;
		alive = false;
		timeOfDeath = SDL_GetTicks();

		handleDeath();
		knockBack = true; // Always knock back dead people

		Game::getInstance()->getPlayer()->addScore(pointsValue);
	}
	else
	{
		health -= amount;
	}

	if(knockBack && attacker != NULL){
		// Determine knock back direction...
		int dir;

		float attackerU = attacker->getU();
		if(attackerU != 0.0f){
			// Use attacker's horizontal velocity if it has one
			dir = (int) (attackerU / fabsf(attackerU));
		}else{
			// Else use the direction the attack's facing
			dir = attacker->isFlipped() ? -1 : 1;
		}

		// Set knockback velocity
		u = 5.0f * dir;

		flipped = (dir == 1);
	}
}
